import datetime, re
from django.contrib.gis.db import models
from django.contrib.gis import admin
from django.contrib.localflavor.us.models import PhoneNumberField, USStateField
from aggregator.models import Feed


class Boundary(models.Model):
    
    CLASS_CHOICES=(
        ('stbr', 'StateBoundary'),
        ('ctbr', 'CityBoundary'),
        ('nycb', 'NYCityBoundary'))

    class_type = models.CharField(
                    max_length=4, 
                    choices=CLASS_CHOICES,
                    db_index=True)

    BTYPE_CHOICES=()
    # Boundary type
    bnd_type = models.CharField(
                max_length=3, 
                choices=BTYPE_CHOICES,
                db_index=True)

    district = models.PositiveIntegerField()
    state = USStateField()
    geom = models.GeometryField()

    def get_pboundary(self):
        """
        Get polymorphic boundary.
        returns an instance of a Boundary subclass.
        """
        if self.class_type == 'stbr':
            return self.stateboundary
        elif self.class_type == 'ctbr':
            return self.cityboundary
        elif self.class_type == 'nycb':
            return self.cityboundary.nycityboundary
         
    def save(self, force_insert=False, force_update=False):
        self.class_type = self.get_class_type()
        super(Boundary, self).save(force_insert, force_update) 

class StateBoundary(Boundary):

    BTYPE_CHOICES=(
        ('sen', 'senate'),
        ('hou', 'house'),
        ('cng', 'congress'))

    def get_class_type(self):
        return 'stbr'

class CityBoundary(Boundary):
    """
    A ward boundary
    """
    BTYPE_CHOICES=(('wrd', 'Ward'),)

    city = models.CharField(max_length=200,)

    def get_ward_label(self):
        return 'Ward'

    def get_class_type(self):
        return 'ctbr'

class NYCityBoundary(CityBoundary):

    BTYPE_CHOICES = CityBoundary.BTYPE_CHOICES + (
        ('bor', 'borough'),
        ('com', 'community'))

    #btype = models.CharField(
    #            max_length=3, 
    #            choices=BTYPE_CHOICES, 
    #            db_index=True)

    def get_ward_label(self):
        return 'City Council'

    def get_class_type(self):
        return 'nycb'

#class Boundary(models.Model):
#    """
#    Defines:
#        Ward Boundary
#        State Senate Boundary
#        State House/Congress Boundary
#        Federal House/Congress Boundary
#    """
#    type_choices = (
#        ('wrd','Ward'),
#        ('sen','Senate'),
#        ('hou','House'),
#        ('cng','Congress'))
#    type = models.CharField(max_length=3, choices=type_choices, db_index=True)
#    district = models.PositiveIntegerField()
#    state = USStateField()
#    city = models.CharField(max_length=200, null=True)
#    geom = models.GeometryField()

class Rep(models.Model):
    """
    Define a representative who can have more than one news feed and belongs
    to a boundary.
    """
    district = models.PositiveIntegerField()
    state = USStateField()
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    middle_name = models.CharField(max_length=50,blank=True)
    nick_name = models.CharField(max_length=50,blank=True)
    slug = models.SlugField(unique=True)
    telephone = PhoneNumberField(blank=True)
    address = models.CharField(max_length=200,blank=True)
    bio = models.TextField(blank=True)
    # Allow more than one news source for a rep.
    feeds = models.ManyToManyField(Feed)
    # a rep can be attached to the same boundary, i.e. senators attached 
    # to the same state.
    boundary = models.ForeignKey(Boundary)

    def __unicode__(self):
        return "%s %s %s %s" % (
                self.first_name, 
                self.nick_name, 
                self.middle_name, 
                self.last_name)

    def get_boundary_links(self):
        """Yuck.  Linking up relations for admin."""
        links = []
        for boundary in self.boundary_set.all():
            links.append('<a href="/admin/core/boundary/%s">%s</a>' %  (boundary.id, boundary))
        return ', '.join(links)
    get_boundary_links.allow_tags = True

    def get_feed_links(self):
        links = []
        for f in self.feeds.all():
            links.append(
                '<a href="/admin/aggregator/feeditem/?feed__id__exact=%s">%s</a> (%s)' % (f.feed.id,f.feed,len(f.feed.feeditem_set.all())))
        return ', '.join(links)

    get_feed_links.allow_tags = True

    def google_feed_url(self):
        query_str = str(self)
        return 'http://news.google.com/news?q="%s"&ie=UTF-8&nolr=1&output=rss' % query_str.replace(' ','+')

    def google_public_url(self):
        query_str = str(self)
        return 'http://news.google.com/news?q="%s"&ie=UTF-8&nolr=1' % query_str.replace(' ','+')

        #return 'http://news.search.yahoo.com/news/rss?p=%s+chicago&ei=UTF-8' % query_string.replace(' ','+')
        #return 'http://news.google.com/news?ned=us&topic=h&output=rss'
    class Meta:
        ordering = ('last_name',)

class SubscriptionManager(models.GeoManager):

    def active(self):
        return self.filter(remove=False, confirmed=True)

    def confirm_sub(self, key):
        """Check if the confirmation key is correct, return a subscription
        object if so.  Otherwise return False.
        """
        if SHA1_RE.search(key):
            try:
                sub = self.get(confirm_key=key)
            except self.model.DoesNotExist:
                return False
            expires = datetime.timedelta(days=CONFIRM_EXPIRES)
            if not sub.created + expires <= datetime.datetime.now():
                sub.confirmed = True
                sub.save()
                return sub
        return False

class Subscription(models.Model):
    """
    Maintain a list of email addresses and reps to send mail to.
    """

    email = models.EmailField(db_index=True)
    boundaries = models.ManyToManyField(Boundary)
    point  = models.PointField()
    place = models.CharField(max_length=150,db_index=True)
    feed = models.CharField(max_length=150,db_index=True)
    remove = models.BooleanField(default=False,db_index=True)
    created = models.DateTimeField(auto_now_add=True)
    confirmed = models.BooleanField(default=False,db_index=True)
    confirm_key = models.CharField(max_length=40)
    objects = SubscriptionManager()

    def __unicode__(self):
        return self.email

    def get_reps(self):
        """Return list of current reps for this subscriber."""
        self.boundaries.rep_set.all()

    class Meta:
        unique_together = (("email", "feed"),)
